package com.yzy.jvm;

/**
 * LVT (local variable table) 局部变量表
 * 局部变量表的容量是以变量槽(variable slot) 为最小单位, 虚拟机规范中并没有指明这个slot的内存占用大小，但是说到每个slot都需要能存放一个boolean,byte,char,short,int,float,reference和returnAddress
 * 对应64位的数据类型，如long和double(reference类型可能是32位也可能是64位)，需要两个连续的slot来存储
 *
 * 如果执行的方法是实例方法那局部变量表中的第0位索引对应的slot默认是用于传递方法所属对应实例的引用，在方法中可以通过this关键字访问
 *
 * 为了节省栈帧空间，局部变量表中的slot是可以重用的，如方法体中定义的变量，其作用域并不一定覆盖整个作用域，那这个变量对应的slot就可以交给其他变量使用
 * 在某些情况下，slot复用会直接影响到系统的垃圾收集行为，如下
 *
 * 在运行参数上加上 -verbose:gc 可以打印gc信息
 *
 * ***下面的代码运行情况仅在jvm解释执行时有效，如果被JIT编译后执行可能会不同
 */
public class TestLVTSlot {

    // case 1 局部变量表是gc roots的一部分, 局部变量表引用的对象不会被回收
    /*public static void main(String[] args) {
        byte[] a = new byte[64 * 1024 * 1024];

        System.gc();   // 变量a对应的内存没有被回收，原因：局部变量表作为gc root的一部分，方法没退出，所以局部变量变还存在，且局部变量表中的slot对应的变量a还有引用，所以不会被回收
        *//**
         [GC (System.gc())  72090K->66663K(251392K), 0.0010383 secs]
         [Full GC (System.gc())  66663K->66422K(251392K), 0.0054932 secs]
         *//*
    }*/

    // case 2 引用手动存在
    /*public static void main(String[] args) {
        byte[] a = new byte[64 * 1024 * 1024];
        a = null;
        System.gc();   // 变量a对应的内存被回收，原因：局部变量表作为gc root的一部分，虽然方法没退出，且局部变量变还存在，但是局部变量表中的slot对应的变量a对堆内存的引用断开了(a = null)，所以对象被回收
        *//**
     [GC (System.gc())  72090K->66591K(251392K), 0.0010896 secs]
     [Full GC (System.gc())  66591K->886K(251392K), 0.0049741 secs]
     *//*
    }*/

    // case 3 变量a的作用域未失效，slot未被复用，引用存在
    /*public static void main(String[] args) {
        byte[] a = new byte[64 * 1024 * 1024];
        int b = 0;
        System.gc();   // 变量a对应的内存未被回收，原因：局部变量表作为gc root的一部分，方法没退出，所以局部变量变还存在
        *//**
         [GC (System.gc())  72090K->66615K(251392K), 0.0011580 secs]
         [Full GC (System.gc())  66615K->66422K(251392K), 0.0055328 secs]
         *//*
    }*/

    // case 4 变量a的作用域已失效，但是slot还未被复用，引用存在
    public static void main(String[] args) {
        {
            byte[] a = new byte[64 * 1024 * 1024];
        }
        System.gc();   // 变量a对应的内存未被回收，原因：变量a虽然在当前作用域之外，但是方法未退出，局部变量表还是作为gc root的一部分，所以a对应的未被回收
        /**
         [GC (System.gc())  72090K->66639K(251392K), 0.0010378 secs]
         [Full GC (System.gc())  66639K->66422K(251392K), 0.0053058 secs]
         */
    }

    // case 5  变量a的作用域已失效，slot被复用，引用断开
    /*public static void main(String[] args) {
        {
            byte[] a = new byte[64 * 1024 * 1024];
        }
        int b = 0;
        System.gc();   // 变量a对应的内存被回收，原因：变量a在当前作用域之外，虽然方法未退出，局部变量表还是作为gc root的一部分，但是a对应的slot槽被b复用了，所以a对应的内存被回收了
        *//**
         [GC (System.gc())  72090K->66623K(251392K), 0.0012332 secs]
         [Full GC (System.gc())  66623K->886K(251392K), 0.0056086 secs]
         *//*
    }*/

}
